﻿/**
 * Peter
 * Created by: Peter Development Team
 *    http://peter.codeplex.com/
 * 
 * GNU General Public License version 2 (GPLv2)
 *    http://peter.codeplex.com/license
 *
 *  This code is provided on an AS IS basis, with no WARRANTIES,
 *  CONDITIONS or GUARANTEES of any kind.
 *
 **/

using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Peter.Common.MainMenu;
using Peter.Common.Utilities;
using Peter.Ftp.Data;
using Peter.Ftp.Logic;
using Peter.Ftp.Tests.DataAccess;

namespace Peter.Ftp.Tests.Logic
{
   /// <summary>
   /// Tests for the model ftp object.
   /// </summary>
   [TestClass]
   public class ModelFtpTests
   {
      /// <summary>
      /// Tests the constructor for ModelFtp.
      /// </summary>
      [TestMethod]
      public void TestConstructor ()
      {
         using (var model = new ModelFtp ())
         {
            Assert.AreEqual ("FTP", model.Title);
            Assert.AreEqual (MainMenuIcon.Ftp, model.Icon);
            Assert.IsNotNull (model.FtpItems);
            Assert.IsNotNull (model.MenuItems);
            Assert.IsTrue (model.MenuItems.Count > 0);
            Assert.IsTrue (model.MenuItems [0].Children.Any (item => item.ToolTip == "Refresh"));
         }
      }

      /// <summary>
      /// Tests the load connection command.
      /// </summary>
      [TestMethod]
      public async Task TestLoadConnection ()
      {
         using (var model = new ModelFtp ())
         {
            Assert.IsTrue (model.LoadConnection.CanExecute (null));
            Assert.IsTrue (model.LoadConnection.CanExecute (FtpConnectionTests.ConnectionData));
            model.LoadConnection.Execute (FtpConnectionTests.ConnectionData);
            await Task.Delay (2000);
            Assert.IsTrue (model.FtpItems.Count > 0);
            Assert.IsFalse (model.LoadConnection.CanExecute (FtpConnectionTests.ConnectionData));
            Assert.AreEqual (3, model.FtpItems[0].Children.Count);
         }
      }

      /// <summary>
      /// Tests adding new connections.
      /// </summary>
      [TestMethod]
      public void TestConnectionsChanged ()
      {
         var peter = new MockPeter ();
         using (var model = new ModelFtp ())
         {
            var catalog = new AssemblyCatalog (Assembly.GetExecutingAssembly ());
            var container = new CompositionContainer (catalog);
            container.ComposeParts (peter, model);

            Assert.AreEqual (2, model.MenuItems[0].Children.Count);
            Assert.AreEqual (3, model.MenuItems[0].Children[0].Children.Count);
            var connection = FtpConnectionTests.ConnectionData.CloneProperties ();
            connection.Server = "iinall.com";
            var ftpOptions = model.PeterOptions.GetOptionPage (OptionsFtp.PAGE_NAME);
            ((OptionsFtp)ftpOptions).FtpConnections.Add (connection);
            Assert.AreEqual (4, model.MenuItems[0].Children[0].Children.Count);

            catalog.Dispose ();
            container.Dispose ();
         }
      }

      /// <summary>
      /// Test the show manage connections command.
      /// </summary>
      [TestMethod]
      public void TestShowManageConnections ()
      {
         var peter = new MockPeter ();
         using (var model = new ModelFtp ())
         {
            var catalog = new AssemblyCatalog (Assembly.GetExecutingAssembly ());
            var container = new CompositionContainer (catalog);
            container.ComposeParts (peter, model);

            Assert.IsNotNull (model.ManageConnections);
            Assert.IsTrue (model.ManageConnections.CanExecute (null));
            model.ManageConnections.Execute (null);
            Assert.IsTrue (peter.ShowOptionsCalled);

            catalog.Dispose ();
            container.Dispose ();
         }
      }

      /// <summary>
      /// Tests the open item command.
      /// </summary>
      [TestMethod]
      public async Task TestOpenItem ()
      {
         var peter = new MockPeter ();
         using (var model = new ModelFtp ())
         {
            var catalog = new AssemblyCatalog (Assembly.GetExecutingAssembly ());
            var container = new CompositionContainer (catalog);
            container.ComposeParts (peter, model);

            Assert.IsFalse (model.ExecuteCommand.CanExecute (null));
            model.LoadConnection.Execute (FtpConnectionTests.ConnectionData);
            await Task.Delay (2000);
            model.SelectedItem = model.FtpItems[0];
            Assert.IsFalse (model.ExecuteCommand.CanExecute (null));
            model.SelectedItem = (FtpItem) model.FtpItems[0].Children [0];
            Assert.IsFalse (model.ExecuteCommand.CanExecute (null));
            model.SelectedItem = (FtpItem)model.FtpItems[0].Children[1];
            Assert.IsTrue (model.ExecuteCommand.CanExecute (null));

            var itemDir = model.SelectedItem.GetDirectory ();
            var file = string.Format ("Peter.FTP/{0}/{1}{2}", FtpConnectionTests.ConnectionData.Server,
               FtpConnectionTests.ConnectionData.UserName, itemDir) + model.SelectedItem.Text;
            var fileInfo = new FileInfo (file);
            if (fileInfo.Exists)
               fileInfo.Delete ();
            model.ExecuteCommand.Execute (null);
            await Task.Delay (2000);
            Assert.IsTrue (File.Exists (file));
            Assert.AreEqual (peter.LastFileOpenRequest, fileInfo.FullName);

            // Reset the last open file...
            peter.Open (string.Empty);
            model.ExecuteCommand.Execute (null);
            await Task.Delay (2000);
            Assert.AreEqual (peter.LastFileOpenRequest, fileInfo.FullName);

            catalog.Dispose ();
            container.Dispose ();
         }
      }

      /// <summary>
      /// Tests the refresh command.
      /// </summary>
      [TestMethod]
      public async Task TestRefresh ()
      {
         using (var model = new ModelFtp ())
         {
            model.LoadConnection.Execute (FtpConnectionTests.ConnectionData);
            await Task.Delay (2000);
            Assert.IsNotNull (model.Refresh);
            Assert.IsFalse (model.Refresh.CanExecute (null));
            model.SelectedItem = model.FtpItems [0];
            Assert.AreEqual (3, model.FtpItems[0].Children.Count);
            Assert.IsTrue (model.Refresh.CanExecute (null));
            model.Refresh.Execute (null);
            await Task.Delay (2000);
            Assert.AreEqual (3, model.FtpItems[0].Children.Count);

            model.SelectedItem = (FtpItem)model.FtpItems[0].Children[0];
            Assert.IsTrue (model.Refresh.CanExecute (null));
            model.Refresh.Execute (null);
            await Task.Delay (2000);
            Assert.AreEqual (2, model.FtpItems[0].Children[0].Children.Count);
         }
      }
   }
}
